/*
 * Copyright (C) 2015-2017 Alibaba Group Holding Limited
 */

#include <stdio.h>
#include <stdint.h>

#include "k_config.h"
#include "k_api.h"
#include "aos/kernel.h"
#include "aos/hal/gpio.h"
#include "aos/hal/uart.h"
#include "aos/hal/i2c.h"
#include "aos/hal/can.h"

#include "pin_mux.h"
#include "hal_gpio.h"

#ifdef WITH_LWIP
#include "lwip/opt.h"
#include "lwip/netif.h"
#include "lwip/tcpip.h"
#include "lwip/inet.h"

#include "ethernetif.h"
#endif
#include "hal_uart.h"
#include "soc_init.h"

#if defined (__CC_ARM) && defined(__MICROLIB)
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#define GETCHAR_PROTOTYPE int fgetc(FILE *f)
#elif defined(__ICCARM__)
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#define GETCHAR_PROTOTYPE int fgetc(FILE *f)
#else
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
   set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#define GETCHAR_PROTOTYPE int __io_getchar(void)
#endif /* defined (__CC_ARM) && defined(__MICROLIB) */

uart_mapping_s st_uart_mapping_table[PORT_UART_SIZE] =
{
    {PORT_UART_STD,   LPUART3, 512},
    {PORT_UART_485_1, LPUART2, 2048},
    {PORT_UART_485_2, LPUART4, 2048},
    {PORT_UART_232_P9, LPUART6, 2048},
    {PORT_UART_TTL_P12, LPUART1, 2048},
    {PORT_UART_TTL_P14, LPUART8, 2048}
};

const gpio_mapping_t gpio_mapping_table[] = {
    {PORT_GPIO_DO_1, {GPIO3, 15}, NULL},
    {PORT_GPIO_DO_2, {GPIO3, 14}, NULL},
    {PORT_GPIO_DO_3, {GPIO3, 16}, NULL},
    {PORT_GPIO_DO_4, {GPIO3, 26}, NULL},
    {PORT_GPIO_DO_5, {GPIO3, 27}, NULL},
    {PORT_GPIO_DO_6, {GPIO2, 24}, NULL},
    {PORT_GPIO_DO_7, {GPIO2, 23}, NULL},
    {PORT_GPIO_DO_8, {GPIO2, 25}, NULL},
    {PORT_GPIO_DI_1, {GPIO2, 27}, NULL},
    {PORT_GPIO_DI_2, {GPIO2, 22}, NULL},
    {PORT_GPIO_DI_3, {GPIO2, 20}, NULL},
    {PORT_GPIO_DI_4, {GPIO2, 21}, NULL},
    {PORT_GPIO_DI_5, {GPIO2, 26}, NULL},
    {PORT_GPIO_DI_6, {GPIO2, 31}, NULL},
    {PORT_GPIO_DI_7, {GPIO2, 30}, NULL},
    {PORT_GPIO_DI_8, {GPIO2, 28}, NULL},
    {PORT_GPIO_EM_STOP, {GPIO1, 11}, NULL},
};

const uint32_t g_u32_gpio_num = ARRAY_SIZE(gpio_mapping_table);

can_mapping_t can_mapping_table[] =
{
    { PORT_CAN_IO,       CAN2, NULL, NULL, NULL },
    { PORT_CAN_RESERVED, CAN1, NULL, NULL, NULL }
};

/* Global Variable for VFS DEBUG Output */
uart_dev_t uart_0 = {
    .port = PORT_UART_STD,                                                              /* uart port */
    .config = {115200, DATA_WIDTH_8BIT, NO_PARITY, STOP_BITS_1, FLOW_CONTROL_DISABLED}, /* uart config */
    .priv = NULL                                                                        /* priv data */
};

uart_dev_t uart_485_1 = {
    .port = PORT_UART_485_1,                                                            /* uart port */
    .config = {115200, DATA_WIDTH_8BIT, NO_PARITY, STOP_BITS_1, FLOW_CONTROL_DISABLED}, /* uart config */
    .priv = NULL                                                                        /* priv data */
};

/*can not be used at the same time with debug uart port*/
uart_dev_t uart_485_2 = {
    .port = PORT_UART_485_2,                                                            /* uart port */
    .config = {115200, DATA_WIDTH_8BIT, NO_PARITY, STOP_BITS_1, FLOW_CONTROL_DISABLED}, /* uart config */
    .priv = NULL                                                                        /* priv data */
};

uart_dev_t uart_232_p9 = {
    .port = PORT_UART_232_P9,                                                            /* uart port */
    .config = {115200, DATA_WIDTH_8BIT, NO_PARITY, STOP_BITS_1, FLOW_CONTROL_DISABLED}, /* uart config */
    .priv = NULL                                                                        /* priv data */
};

uart_dev_t uart_ttl_p12 = {
    .port = PORT_UART_TTL_P12,                                                            /* uart port */
    .config = {115200, DATA_WIDTH_8BIT, NO_PARITY, STOP_BITS_1, FLOW_CONTROL_DISABLED}, /* uart config */
    .priv = NULL                                                                        /* priv data */
};

uart_dev_t uart_ttl_p14 = {
    .port = PORT_UART_TTL_P14,                                                               /* uart port */
    .config = {115200, DATA_WIDTH_8BIT, NO_PARITY, STOP_BITS_1, FLOW_CONTROL_DISABLED}, /* uart config */
    .priv = NULL                                                                        /* priv data */
};


#ifdef WITH_LWIP
extern struct netif fsl_netif0[];
#endif
extern void tcp_init(void);
extern void udp_init(void);

int lwip_tcpip_init(void);


gpio_mapping_t* get_drv_manu_info(gpio_dev_t *gpio)
{
    uint32_t i = 0;

    for (i = 0; i < g_u32_gpio_num; i++) {
        if (gpio_mapping_table[i].port == gpio->port) {
            return &gpio_mapping_table[i];
        }
    }

    return NULL;
}

const st_gpio_opt_t* get_gpio_opt(gpio_dev_t *gpio)
{
    return &g_stmimx_gpio_opt;

}

static void stduart_init(void)
{
    hal_uart_init(&uart_0);
}

void board_peripheral_init(void)
{
    /*default uart init*/
    stduart_init();
}

/* Get debug console frequency. */
uint32_t BOARD_DebugConsoleSrcFreq(void)
{
    uint32_t freq;

    /* To make it simple, we assume default PLL and divider settings, and the only variable
       from application is use PLL3 source or OSC source */
    if (CLOCK_GetMux(kCLOCK_UartMux) == 0) /* PLL3 div6 80M */
    {
        freq = (CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6U) / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
    }
    else
    {
        freq = CLOCK_GetOscFreq() / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
    }

    return freq;
}

void platform_init(void)
{
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
}

#ifdef WITH_LWIP
static void tcpip_init_done(void *arg)
{
    long long ts = aos_now();
    srand((unsigned int)ts);
    tcp_init();
    udp_init();

#if LWIP_IPV4
    ip4_addr_t ipaddr, netmask, gw;
    memset(&ipaddr, 0, sizeof(ipaddr));
    memset(&netmask, 0, sizeof(netmask));
    memset(&gw, 0, sizeof(gw));
    ip4addr_aton("192.168.1.220", &ipaddr);
    ip4addr_aton("255.255.255.0", &netmask);
    //gw = inet_addr("192.168.1.220");
    netif_add(&fsl_netif0[0], &ipaddr, &netmask, &gw, NULL, ethernetif0_init, tcpip_input);
#endif

#if LWIP_IPV6
#if !LWIP_IPV4
    netif_add(&fsl_netif0[0], NULL, ethernetif0_init, tcpip_input);
#endif
    netif_create_ip6_linklocal_address(&fsl_netif0[0], 1);
    fsl_netif0[0].ip6_autoconfig_enabled = 1;
#endif

    netif_set_default(&fsl_netif0[0]);
    netif_set_up(&fsl_netif0[0]);
    //tcpip_dhcpc_start(&fsl_netif0[0]);
    printf("TCP/IP initialized.");
}

int lwip_tcpip_init(void)
{
    tcpip_init(tcpip_init_done, NULL);

    return 0;
}
#endif

/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
    krhino_intrpt_enter();
    krhino_tick_proc();
    krhino_intrpt_exit();
}

/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
    if (ch == '\n')
    {
        //hal_uart_send(&console_uart, (void *)"\r", 1, 30000);
        hal_uart_send(&uart_0, (void *)"\r", 1, 30000);
    }
    hal_uart_send(&uart_0, &ch, 1, 30000);
    return ch;
}

/**
  * @brief  Retargets the C library scanf function to the USART.
  * @param  None
  * @retval None
  */
GETCHAR_PROTOTYPE
{
    /* Place your implementation of fgetc here */
    /* e.g. readwrite a character to the USART2 and Loop until the end of transmission */
    uint8_t ch = EOF;
    int32_t ret = -1;

    uint32_t recv_size;
    ret = hal_uart_recv_II(&uart_0, &ch, 1, &recv_size, HAL_WAIT_FOREVER);

    if (ret == 0)
    {
        return ch;
    }
    else
    {
        return -1;
    }
}

